package main.java.person.fjsp.algorithm.ga;

import main.java.person.fjsp.algorithm.ga.entity.Individual;
import main.java.person.fjsp.algorithm.ga.utils.GAUtils;
import main.java.person.fjsp.common.entity.*;

import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.IntStream;

/**
 * 遗传算法
 *
 * @author xcy
 */
public class GASolver {
    /**
     * 初始种群规模
     */
    private final int initialPopSize;
    /**
     * 选择过程中，精英选择的数量，余下的采用锦标赛选择。精英选择不能超过种群规模的1/2
     */
    private final int eSize;
    /**
     * 要进行锦标赛的个体数量
     */
    private int tNum = 3;
    /**
     * 交叉概率
     */
    private final double crossoverProbability;
    /**
     * 变异概率
     */
    private final double mutationProbability;
    /**
     * 最大迭代次数
     */
    private final int epochs;
    /**
     * 最大计算时间（ms）
     */
    private long maxCalTime = 36000;
    /**
     * 最大忍耐无更优解的代数
     */
    private final int maxNoBetterNum;
    private GAUtils gaUtils=new GAUtils();
    /**
     * 产生随机数
     */
    private final Random random = new Random();


    public GASolver(int initialPopSize, int eSize, double crossoverProbability, double mutationProbability, int epochs, int maxNoBetterNum) {
        this.initialPopSize = initialPopSize;
        this.eSize = eSize;
        this.crossoverProbability = crossoverProbability;
        this.mutationProbability = mutationProbability;
        this.epochs = epochs;
        this.maxNoBetterNum = maxNoBetterNum;
    }

    /**
     * 算法主入口
     */
    public Individual solve(DataManager dataManager) throws Exception {
        Individual bestIndividual = null;
        int noBetterNum = 0;
        long beginTime = System.currentTimeMillis();
        //生成初始种群
        ArrayList<Individual> individuals = gaUtils.generateInitialPopulation(dataManager,initialPopSize);
        for (int i = 0; i < this.epochs; i++) {
            System.out.println("==========第"+(i+1)+"代==========");
            //解码，得到个体适应值
            for (Individual individual : individuals) {
                individual.setFitness(1 / gaUtils.decode(individual, dataManager));
            }
            //选择
            ArrayList<Individual> selectIndividuals = gaUtils.selection(individuals,eSize,tNum);
            System.out.println("当代最优个体适应值："+selectIndividuals.get(0).getFitness());
            if (i == 0) {
                //第一代最佳个体是选择的最佳个体
                bestIndividual = selectIndividuals.get(0).clone();
            } else {
                //比较最佳个体与选择的最佳个体的适应值，如果更优替代，如果没有更优，忍耐次数+1
                if (bestIndividual.getFitness() < selectIndividuals.get(0).getFitness()) {
                    bestIndividual = selectIndividuals.get(0).clone();
                    noBetterNum = 0;
                } else {
                    noBetterNum++;
                }
            }
//            System.out.println("历代最优个体适应值："+bestIndividual.getFitness());
            if (this.maxNoBetterNum <= noBetterNum) {
                System.out.println("一定代数无更优解，退出");
                break;
            }
            if ((System.currentTimeMillis() - beginTime) >= this.maxCalTime) {
                System.out.println("达到允许的计算时间，退出");
                break;
            }
            //种群交叉与变异
            ArrayList<Individual> offSprings = gaUtils.popCrossoverAndMutation(selectIndividuals,crossoverProbability,mutationProbability, dataManager);

            individuals = offSprings;
        }
        return bestIndividual;
    }



    public void setMaxCalTime(long maxCalTime) {
        this.maxCalTime = maxCalTime;
    }

    public void settNum(int tNum) {
        this.tNum = tNum;
    }
}
